@file:Suppress("SpellCheckingInspection")

package han.cirno.corrupt.components.school.impl.fjut

import android.util.Base64
import han.cirno.corrupt.R
import han.cirno.corrupt.components.school.SchoolImpl
import han.cirno.corrupt.components.school.SchoolProvider
import han.cirno.corrupt.components.school.impl.CommonNetClient
import han.cirno.corrupt.throwables.LoginExceptions
import han.cirno.corrupt.util.OkHttpUtil.quickCall
import okhttp3.FormBody
import okhttp3.Request
import okhttp3.Response
import org.jsoup.Jsoup
import javax.crypto.Cipher
import javax.crypto.spec.IvParameterSpec
import javax.crypto.spec.SecretKeySpec

/**
 * 糟蹋就完了
 * @author CCirno
 */
class FjutEduClient: CommonNetClient<FjutEduConst.Payload>(
    {Request.Builder().url(LOOPBACK_2_URL).build()},
    { FjutEduConst.isLoopBackedToLogin(it) }
) {
    companion object{
        val instance: FjutEduClient = FjutEduClient()
        const val LOOPBACK_1_URL="https://webvpn.fjut.edu.cn/users/sign_in"
        const val LOOPBACK_2_URL="https://nids-443.webvpn.fjut.edu.cn/authserver/login?service=https%3A%2F%2Fjwxt-443.webvpn.fjut.edu.cn%2Fsso%2Fjziotlogin"
        const val LOOPBACK_1_HOST="webvpn.fjut.edu.cn"
        const val LOOPBACK_2_HOST="nids-443.webvpn.fjut.edu.cn"
    }

    override fun tryLogin(tryLoginResponse: Response){
        val (response,loopBackLevel)=tryLoginResponse.use {
            val returnUrlHost = it.request.url.host
            val string = it.body?.string()
            return@use string to when (returnUrlHost){
                LOOPBACK_1_HOST -> 2
                LOOPBACK_2_HOST -> 1
                else -> 0
            }
        }
        if (response==null)throw NullPointerException("Response is null")
        val data = SchoolImpl.impl!!.dataOperation()
        val username = data.singleGet(SchoolProvider.KEY_ID, String::class)!!
        val password=data.singleGet(SchoolProvider.KEY_PASSWORD,String::class)!!
        if (loopBackLevel >=2){
            val document=Jsoup.parse(response)
            val formBody = FormBody.Builder()
                .addEncoded("utf8", "%E2%9C%93")
                .add("authenticity_token", document.getElementsByAttributeValue("name", "csrf-token").attr("content"))
                .add("user[login]", username)
                .add("user[password]", password)
                .add("user[dymatice_code]", "unknown")
                .add("user[otp_with_capcha]", "false")
                .addEncoded("commit", "%E7%99%BB%E5%BD%95+Login")
                .build()
            okHttpClient.quickCall(Request.Builder()
                .url(LOOPBACK_1_URL)
                .post(formBody))
                .use {
                    if (it.request.url.host== LOOPBACK_1_HOST)
                        throw IllegalStateException("Loop backed")
                }
        }
        if (loopBackLevel >=1){
            val body=okHttpClient.quickCall(Request.Builder().url(LOOPBACK_2_URL)).use { it.body!!.string() }
            val document=Jsoup.parse(body)
            val execution = document.getElementById("pwdLoginDiv")!!.getElementsByAttributeValue("name", "execution").attr("value")
            val salt=document.getElementById("pwdEncryptSalt")!!.attr("value")
            val formBody = FormBody.Builder()
                .add("username", username)
                .add("password",aesEncryptTest(password,salt))
                .add("captcha","")
                .add("_eventId","submit")
                .add("cllt","userNameLogin")
                .add("dllt","generalLogin")
                .add("lt","")
                .add("execution",execution)
                .build()
            val result=okHttpClient.quickCall(Request.Builder()
                .url(LOOPBACK_2_URL)
                .post(formBody)).use {
                    FjutEduConst.isLoopBackedToLogin(it.request.url) to it.isSuccessful }
            if (!result.first)
                return
            if(result.second) {
                val errorMsg = document.getElementById("showErrorTip")!!.attr("title")
                if (errorMsg.contains("该账号非常用账号或用户名密码有误"))
                    throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_password_unknown_times,null)
                if (errorMsg.contains("入密码"))
                    throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_emptyPassword,null)
                if (errorMsg.contains("入用户名"))
                    throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_emptyUsername,null)
                throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_other,null)
            }
            throw LoginExceptions.InvalidDataExceptionWithResId(R.string.login_error_login_invalidData_other,null)
        }
    }

    private fun aesEncryptTest(password:String,salt:String):String{
        val ori="0000000000000000000000000000000000000000000000000000000000000000$password"
        val iv= "0000000000000000"
        val cipher= Cipher.getInstance("AES/CBC/PKCS5Padding")
        val keySpec = SecretKeySpec(salt.toByteArray(), "AES")
        val ivParameterSpec = IvParameterSpec(iv.toByteArray())
        cipher.init(Cipher.ENCRYPT_MODE,keySpec,ivParameterSpec)
        val final = cipher.doFinal(ori.toByteArray())
        return Base64.encodeToString(final, Base64.DEFAULT)
    }
}